/*
* Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  An active object for passing an NDEF message to an application
*               using a global shared memory chunk.
*/

#ifndef __MESSAGEHANDLER_H__
#define __MESSAGEHANDLER_H__

#include <e32base.h>

class CAknGlobalNote;
class CNdefMessage;

/**
 * Active object for handling an NDEF message by sharing it with an application.
 *
 * The entry point for the message processing is the function HandleNdefMessage().
 *
 * HandleNdefMessage() sanity checks the NDEF message, and if it passes, starts
 * the asynchronous message processing. The asynchronous steps involve writing
 * the NDEF message in its entirety to shared memory and starting the application
 * that will actually handle the message.
 */
class CMessageHandler : public CActive
{
public:

    /**
     * Symbian two-phased constructor.
     *
     * Instantiates an object of type CMessageHandler.
     *
     * @return Pointer to the newly creates instance, ownership of the object
     *   is transferred to the caller.
     */
    static CMessageHandler* NewL();

    /**
     * C++ destructor.
     */
    virtual ~CMessageHandler();

    /**
     * Starts the NDEF message handling.
     *
     * The request status passed to this function is guaranteed to always get
     * completed, whether or not the message handling is successful or fails
     * with some error. The status code of the request object (i.e. the TInt
     * value returned by TRequestStatus::Int()) will reflect the result of the
     * processing.
     *
     * @param aRequestStatus The request status to be completed when processing
     *  is done.
     * @param aMessage The NDEF message to process, ownership of the object
     *   is transferred to this class.
     */
    void HandleNdefMessage(
        TRequestStatus& aRequestStatus,
        CNdefMessage* aMessage );

protected:

    /**
     * From base class CActive. Cancels the global note shown by this class.
     */
    virtual void DoCancel();

    /**
     * From base class CActive. Called when global note shown by this class has
     * been dismissed by the user.
     */
    virtual void RunL();

    /**
     * From base class CActive. Called if RunL() leaves.
     *
     * In practice this function can never get called, as the implementation of
     * RunL() includes no potentially leaving function calls. The RunError()
     * implementation is included merely for completeness' sake.
     *
     * @param aError The leave code generated from RunL().
     * @return Always returns KErrNone to indicate that the error was handled.
     */
    virtual TInt RunError( TInt aError );

private:

    /**
     * C++ constructor.
     */
    CMessageHandler();

    /**
     * Symbian second phase constructor.
     */
    void ConstructL();

    /**
     * Attempts to open or create the global mutex.
     */
    void OpenMutex();

    /**
     * Attempts to open or create the global shared memory chunk.
     */
    void OpenChunk();

    /**
     * Show a global error note displaying the state of this message handler.
     *
     * This function is called from RunError(). This means that the RunL()
     * function caused a leave, indicating that one of the asynchronous
     * processing steps ended in an error. Under normal operation no dialogs
     * are shown.
     *
     * The values displayed by the error note include various member variables
     * and error codes that may be useful in tracking down exactly which RunL()
     * call caused the issue, and why.
     *
     * @param aError The error code to display in the error note. This is the
     *   same value that was passed in to RunError(), i.e. the Symbian leave
     *   code that RunL() left with.
     */
    void ShowGlobalNoteL( TInt aError );

    /**
     * Writes a time stamp and NDEF message size into the supplied buffer.
     *
     * @param aChunkPtr The buffer into which to write the header information.
     */
    TInt WriteSharedMemoryHeaderL( TPtr8 aChunkPtr );

    /**
     * Writes the NDEF message in its entirety into the supplied buffer.
     *
     * @param aChunkPtr The buffer into which to write the NDEF message.
     */
    TInt WriteSharedMemoryMessageL( TPtr8 aChunkPtr );

    /**
     * Writes header information and the NDEF message into the shared memory chunk.
     */
    void WriteSharedMemoryL();

    /**
     * Starts the NDEF handler application, or brings it to the foreground if it is running.
     */
    void StartApplicationL();

    /**
     * Waits for the NDEF handler application to signal the global semaphore.
     */
    void WaitForApplicationToStartUpL();

    void SetActiveState( TInt aState, TBool aCompleteRequest = EFalse );

    /**
     * Complete a pending NFC Content Handler request.
     *
     * If there is no pending request (i.e. the iRequestStatus member variable
     * is NULL, or its value is not KRequestPending), this function does
     * nothing.
     *
     * @param aError The result code with which to complete the pending request.
     *  KErrNone if the message handling completed successfully, a system-wide
     *  error code otherwise.
     */
    void CompleteRequest( TInt aError );

    /**
     * Cleanup operation to signal mutexes pushed onto the cleanup stack.
     *
     * @param aAny A pointer to the RMutex instance to call Signal() on when
     *   popping and destroying a pointer pushed onto the cleanup stack with a
     *   TCleanupItem using this function as its cleanup operation.
     */
    static void CleanupSignal( TAny* aAny );

private:

    /** Asynchronous steps taken to process an NDEF message. RunL() is called once for each value other than EStateIdle. */
    enum ActiveState {
        EStateIdle,
        EStateWriteSharedMemory,
        EStateStartApplication,
        EStateWaitForApplicationToStartUp
    };

    /** The current state of this active object, EStateIdle if not active. */
    TInt iState;

    /** The request status passed in from the NFC Content Handler, not owned. */
    TRequestStatus* iRequestStatus;

    /** The NDEF message being processed, owned. */
    CNdefMessage* iMessage;

    /** The global error note used to display debug information, owned. */
    CAknGlobalNote* iGlobalNote;

    /** Identifier of the global error note. */
    TInt iGlobalNoteId;

    /** The mutex used to protect access to the shared memory chunk. */
    RMutex iMutex;

    /** The shared memory chunk used to pass information from the plugin to the application. */
    RChunk iChunk;

    /** Semaphore creation error code. If not KErrNone, the semaphore is unavailable. */
    TInt iSemaphoreError;

    /** Mutex creation error code. If not KErrNone, the mutex is unavailable. */
    TInt iMutexError;

    /** Chunk creation error code. If not KErrNone, the chunk is unavailable. */
    TInt iChunkError;
};

#endif // __MESSAGEHANDLER_H__
